﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;

using PostSharp.Laos;

using Arquitetura.Architectural.Model;

namespace Arquitetura.Architectural.Aspect
{
    [Serializable]
    public sealed class TransactioningAttribute : OnMethodBoundaryAspect
    {
        #region Propriedade(s)
        public TransactionScopeOption ScopeOption
        { get; set; }

        public IsolationLevel IsolationLevel
        { get; set; }

        public EnterpriseServicesInteropOption InteropOption
        { get; set; }

        public Single Timeout
        { get; set; }
        #endregion Propriedade(s)

        #region Construtor(es)
        public TransactioningAttribute()
        {
            ScopeOption = TransactionScopeOption.Required;
            IsolationLevel = IsolationLevel.ReadCommitted;
            InteropOption = EnterpriseServicesInteropOption.Automatic;
            Timeout = 60;
        }
        #endregion Construtor(es)

        #region Método(s)
        public override void OnEntry(MethodExecutionEventArgs eventArgs)
        {
            TransactionOptions transactionOptions = new TransactionOptions();
            transactionOptions.Timeout = TimeSpan.FromSeconds(Timeout);
            transactionOptions.IsolationLevel = IsolationLevel;
            eventArgs.MethodExecutionTag = new TransactionScope(ScopeOption, transactionOptions, InteropOption);
        }

        /// <summary>
        /// Method executed <b>after</b> the body of methods to which this aspect is applied.
        /// </summary>
        /// <param name="eventArgs">Event arguments specifying which method is being executed and which are its arguments.</param>
        /// <remarks>
        /// We commit or rollback the transaction that was opened in the <see cref="OnEntry"/> method.
        /// </remarks>
        public override void OnExit(MethodExecutionEventArgs eventArgs)
        {
            TransactionScope transactionScope = eventArgs.MethodExecutionTag as TransactionScope;
            if (eventArgs.Exception == null)
            {
                if (eventArgs.ReturnValue is Result)
                {
                    Result resultado = eventArgs.ReturnValue as Result;
                    if (resultado.Success)
                    {
                        transactionScope.Complete();
                    }
                }
                else
                {
                    transactionScope.Complete();
                }
            }
            transactionScope.Dispose();
        }
        #endregion Método(s)
    }
}
